﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;

using Microsoft.AspNetCore.Http;

namespace zijian666.WebApi
{
    public partial class WebApiOptions
    {
        /// <summary>
        /// 启用RequestBuffering功能, 并设置排除路径表达式
        /// </summary>
        protected Regex? RequestBufferingExcludePathRegex { get; private set; }

        /// <summary>
        /// 是否启用RequestBuffering功能
        /// </summary>
        protected bool UesRequestBuffering { get; private set; }

        // 需要启用RequestBuffering功能的Path路径集合
        private readonly ConcurrentDictionary<string, bool> _requestBufferingPathCache = new(StringComparer.OrdinalIgnoreCase);

        /// <summary>
        /// 确保 request Body 可以多次读取。 通常会将请求正文缓冲到内存中;将大于30000字节的请求写入磁盘。
        /// <br>较大请求的临时文件将写入 ASPNETCORE_TEMP 环境变量中命名的位置（如果有）。 如果未定义该环境变量，则这些文件将写入当前用户的临时文件夹。 文件会在其关联的请求结束时自动删除</br>
        /// </summary>
        /// <param name="excludePathExprs">排除路径的正则表达式或前缀</param>
        public void EnableRequestBuffering(params string[] excludePathExprs)
        {
            UesRequestBuffering = true;
            if (excludePathExprs?.Length > 0)
            {
                var expr = new List<string>();

                foreach (var excludePathExpr in excludePathExprs.SelectMany(x => x.Split('|')))
                {
                    if (excludePathExpr?.Trim() is string str && str.Length > 0)
                    {
                        if (str.StartsWith("^/"))
                        {
                            expr.Add(str[2..].Trim().ToLowerInvariant());
                        }
                        else if (str[0] is '^' or '/')
                        {
                            expr.Add(str[1..].Trim().ToLowerInvariant());
                        }
                        else
                        {
                            expr.Add(str.ToLowerInvariant());
                        }
                    }
                }
                // regex = ^/(xxx|xxx|xxx)
                if (expr.Count > 0)
                {
                    var s = expr.Where(x => x.Length > 0);
                    s = RequestBufferingExcludePathRegex?.ToString()[3..^1].Split('|').Union(s) ?? s.Distinct();

                    RequestBufferingExcludePathRegex = new($"^/({string.Join("|", s.Union(expr).Distinct())})", RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Singleline);
                }
            }
        }


        private partial void EnableBuffering(HttpContext context)
        {
            if (UesRequestBuffering)
            {
                if (RequestBufferingExcludePathRegex is null || !RequestBufferingExcludePathRegex.IsMatch(context.Request.Path))
                {
                    context.Request.EnableBuffering();
                }
            }
        }
    }
}
